package com.autumn.workflow.command.diagram;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
import org.activiti.image.ProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StreamUtils;

import com.autumn.platform.core.Utils;
import com.autumn.workflow.boot.WorkflowProperties;
import com.autumn.workflow.command.ParamCommand;
import com.autumn.workflow.model.ProcessTrace;
import com.autumn.workflow.model.ProcessTraceNode;

public class DiagramCommand implements ParamCommand<String, byte[]> {

    @Autowired
    private WorkflowProperties properties;
    @Autowired
    private DiagramRepository repository;

    @Override
    public byte[] execute(CommandContext commandContext, String procInstId) {
        try {
            // 流程图生成器
            ProcessDiagramGenerator generator = commandContext.getProcessEngineConfiguration().getProcessDiagramGenerator();
            HistoricProcessInstanceEntity instance = commandContext.getHistoricProcessInstanceEntityManager().findById(procInstId);
            if (null == instance) {
                throw new RuntimeException("not fount process instance [" + procInstId + "]");
            }
            BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(instance.getProcessDefinitionId());
            String imageType = "png";

            List<String> highLightedActivities = null;
            List<String> highLightedFlows = null;
            ProcessTrace trace = this.repository.queryProcessTrace(procInstId);
            List<ProcessTraceNode> nodes = trace.getNodes();
            if (null != nodes && !nodes.isEmpty()) {
                //Process process = bpmnModel.getMainProcess();
                highLightedActivities = new ArrayList<>();
                highLightedFlows = new ArrayList<>();
                Map<String, Set<String>> paths = new HashMap<>();
                for (int i = 0, l = nodes.size(); i < l; i++) {
                    ProcessTraceNode node = nodes.get(i);
                    String actId = node.getActId();
                    if (!highLightedActivities.contains(actId)) {
                        highLightedActivities.add(actId);
                    }
                    if (i < l - 1) {
                        Set<String> pSet = paths.get(actId);
                        if (null == pSet) {
                            pSet = new HashSet<>();
                            paths.put(actId, pSet);
                        }
                        pSet.add(nodes.get(i + 1).getActId());
                    }
                }

                for (Process process : bpmnModel.getProcesses()) {
                    Map<String, FlowElement> map = process.getFlowElementMap();
                    if (null != map) {
                        for (Map.Entry<String, FlowElement> entry : map.entrySet()) {
                            String key = entry.getKey();
                            if (entry.getValue() instanceof SequenceFlow) {
                                SequenceFlow flow = (SequenceFlow) entry.getValue();
                                String src = flow.getSourceRef();
                                Set<String> pSet = paths.get(src);
                                if (null != pSet && pSet.contains(flow.getTargetRef()) && !highLightedFlows.contains(key)) {
                                    highLightedFlows.add(key);
                                }
                            }
                        }
                    }
                }
            }
            String fontName = "宋体";
            String activityFontName = properties.getActivityFontName();
            if (Utils.isBlank(activityFontName)) {
                activityFontName = fontName;
            }
            String labelFontName = properties.getLabelFontName();
            if (Utils.isBlank(labelFontName)) {
                labelFontName = fontName;
            }
            String annotationFontName = properties.getAnnotationFontName();
            if (Utils.isBlank(annotationFontName)) {
                annotationFontName = fontName;
            }
            InputStream inputStream = generator.generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, 1.0);
            return StreamUtils.copyToByteArray(inputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
